package jxtend.processor.eclipse.visitor.traverser;

import jxtend.processor.eclipse.utils.ASTNodeUtils;

import org.eclipse.jdt.internal.compiler.ASTVisitor;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.jdt.internal.compiler.lookup.BlockScope;

@SuppressWarnings("restriction")
public class TypeDeclarationTraverser implements ASTNodeChildrenTraverser {

	@Override
	public boolean isApplicable(ASTNode node) {
		return (node instanceof TypeDeclaration);
	}

	@Override
	public void traverseChildren(ASTNode node, ASTVisitor visitor, BlockScope scope) {
		TypeDeclaration typeDeclaration = (TypeDeclaration) node;

		ASTNodeUtils.traverseNullableNode(typeDeclaration.javadoc, visitor, scope);
		ASTNodeUtils.traverseArray(typeDeclaration.annotations, visitor, typeDeclaration.staticInitializerScope);
		ASTNodeUtils.traverseNullableNode(typeDeclaration.superclass, visitor, typeDeclaration.scope);
		ASTNodeUtils.traverseArray(typeDeclaration.superInterfaces, visitor, typeDeclaration.scope);

		if (typeDeclaration.typeParameters != null) {
			int length = typeDeclaration.typeParameters.length;
			for (int i = 0; i < length; i++) {
				typeDeclaration.typeParameters[i].traverse(visitor, typeDeclaration.scope);
			}
		}

		if (typeDeclaration.memberTypes != null) {
			int length = typeDeclaration.memberTypes.length;
			for (int i = 0; i < length; i++)
				typeDeclaration.memberTypes[i].traverse(visitor, typeDeclaration.scope);
		}
		
		if (typeDeclaration.fields != null) {
			int length = typeDeclaration.fields.length;
			for (int i = 0; i < length; i++) {
				FieldDeclaration field;
				if ((field = typeDeclaration.fields[i]).isStatic()) {
					field.traverse(visitor, typeDeclaration.staticInitializerScope);
				} else {
					field.traverse(visitor, typeDeclaration.initializerScope);
				}
			}
		}

		if (typeDeclaration.methods != null) {
			//TODO: the "UndoTypeResolveASTNodeVisitor#clearDefaultConstructor(TypeDeclaration)" invocation from
			//	"ProcessHandlersASTNodeVisitor" causes "typeDeclaration.methods.length" to change;
			//	for now we will just work around this by reevaluating the length each time
//			int length = typeDeclaration.methods.length;

			for (int i = 0; i < typeDeclaration.methods.length; i++)
				typeDeclaration.methods[i].traverse(visitor, typeDeclaration.scope);
		}
	}

}
